//
// Created by user on 20-3-19.
//

#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_

#include "../GeneralLibrary/Linkage.h"
#include "../GeneralLibrary/Printf.h"
#include "../GeneralLibrary/Lib.h"
#include "../ExceptionManagement/Gate.h"
#include "../ProcessManagement/Ptrace.h"

/*======================== 宏变量定义区 ==========================*/

#define NR_IRQS 24

/*======================== 宏函数定义区 ==========================*/
// 保存现场的宏函数
#define SAVE_ALL                \
    "cld;			        \n\t"        \
    "pushq	%rax;		    \n\t"        \
    "pushq	%rax;		    \n\t"        \
    "movq	%es,	%rax;	\n\t"        \
    "pushq	%rax;		    \n\t"        \
    "movq	%ds,	%rax;	\n\t"        \
    "pushq	%rax;		    \n\t"        \
    "xorq	%rax,	%rax;	\n\t"        \
    "pushq	%rbp;		    \n\t"        \
    "pushq	%rdi;		    \n\t"        \
    "pushq	%rsi;		    \n\t"        \
    "pushq	%rdx;		    \n\t"        \
    "pushq	%rcx;		    \n\t"        \
    "pushq	%rbx;		    \n\t"        \
    "pushq	%r8;		    \n\t"        \
    "pushq	%r9;		    \n\t"        \
    "pushq	%r10;		    \n\t"        \
    "pushq	%r11;		    \n\t"        \
    "pushq	%r12;		    \n\t"        \
    "pushq	%r13;		    \n\t"        \
    "pushq	%r14;		    \n\t"        \
    "pushq	%r15;		    \n\t"        \
    "movq	$0x10,	%rdx;	\n\t"        \
    "movq	%rdx,	%ds;	\n\t"        \
    "movq	%rdx,	%es;	\n\t"

#define IRQ_NAME2(nr) nr##Interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)

#define BuildIRQ(nr)                            \
void IRQ_NAME(nr);                        \
__asm__ (    SYMBOL_NAME_STR(IRQ)#nr"Interrupt:		\n\t"    \
            "pushq	$0x00				\n\t"    \
            SAVE_ALL                    \
            "movq	%rsp,	%rdi			\n\t"    \
            "leaq	ret_from_intr(%rip),	%rax	\n\t"    \
            "pushq	%rax				\n\t"    \
            "movq	$"#nr",	%rsi			\n\t"    \
            "jmp	doIRQ	\n\t");

/*======================== 结构体定义区 ==========================*/

typedef struct hwInterruptType hwInterruptController;

// 中断默认操作接口结构体
struct hwInterruptType {
    void (*enable)(unsigned long irq);                      // 使能中断操作接口

    void (*disable)(unsigned long irq);                     // 禁止中断操作接口

    unsigned long (*install)(unsigned long irq, void *arg); // 安装中断操作接口

    void (*uninstall)(unsigned long irq);                   // 卸载中断操作接口

    void (*ack)(unsigned long irq);                         // 应答中断操作接口
};

// 中断处理描述符表结构体
typedef struct {
    hwInterruptController *controller;                      // 中断使能、应答等操作

    char *irqName;                                          // 中断名
    unsigned long parameter;                                // 中断处理函数的参数

    void (*handler)(unsigned long nr, unsigned long parameter, PerformSite *regs);  // 中断处理函数

    unsigned long flags;                                    // 自定义标志位
} IRPDescriptorTable;

/*======================== 外部变量声明区 ==========================*/

// 中断函数数组
extern void (*interrupt[24])(void);

// 中断处理描述符表数组
extern IRPDescriptorTable interruptDescriptor[NR_IRQS];

// SMP IPI 描述符
extern IRPDescriptorTable SMPIPIDesc[10];

// SMP中断函数数组
extern void (*SMPInterrupt[10])(void);

/*======================== 函数声明区 ==========================*/

/**
 * 中断输出函数，根据预编译找到不同的中断控制器的中断输出函数
 * @param regs 寄存器
 * @param nr 中断号
 */
extern void doIRQ(PerformSite *regs, unsigned long nr);

/**
 * 根据中断号将中断的名称、处理函数、参数和控制器住处到 interruptDescriptor 数组中
 * @param irq 中断号
 * @param arg 安装函数的参数
 * @param handler 中断处理函数
 * @param parameter 中断处理函数的参数
 * @param controller 控制器
 * @param irqName 中断名
 * @return 返回 1 或 0
 */
int registerIRQ(unsigned long irq,
                void *arg,
                void (*handler)(unsigned long nr, unsigned long parameter, PerformSite *regs),
                unsigned long parameter,
                hwInterruptController *controller,
                char *irqName);

/**
 * 卸载中断处理函数
 * @param irq 中断号
 * @return 返回 1 或 0
 */
int unregisterIRQ(unsigned long irq);

/**
 * 注册IPI
 * @param irq 中断号
 * @param handler 处理函数
 * @param parameter 处理函数的参数
 * @param controller 控制器
 * @param irqName 中断名
 * @return
 */
int registerIPI(unsigned long irq,
                void (*handler)(unsigned long nr, unsigned long parameter, PerformSite *regs),
                unsigned long parameter,
                hwInterruptController *controller,
                char *irqName);

/**
 * 卸载IPI
 * @param irq 中断号
 * @return
 */
int unRegisterIPI(unsigned long irq);

#endif //_INTERRUPT_H_
